package controller

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"go-0650-blog-grom/dao/mysql"
	"go-0650-blog-grom/models"
	"go-0650-blog-grom/myUtil/jwt"
	"go-0650-blog-grom/service"
	"go.uber.org/zap"
	"net/http"
)

type UserController struct {
}

func (con UserController) TestF(c *gin.Context) {
	fmt.Println("c.Request: ", c.Request)

	// 获取链接中的参数
	fmt.Println("param1: ", c.Query("param1"))

	// 获取请求体中的 JOSN 参数
	var sign *models.SignForm
	// 此时 sign 还是空指针，如果执行下面的指令则会报错, c.BindJSON(&sign) 绑定之后才可以访问
	// fmt.Println(*sign)
	fmt.Println("&sign: ", &sign)

	c.BindJSON(&sign)
	fmt.Println("*sign: ", *sign)
	fmt.Println("sign.UserName: ", sign.UserName)
	fmt.Println("*(*sign).UserName: ", (*sign).UserName)

	// 获取请求头中的参数
	fmt.Println("header1: ", c.GetHeader("header1"))

	c.String(200, "测试路由抽离方法!")
}

/**
 * @Author SSWANG
 * @Description //TODO 注册业务
 * @Date 21:30 2022/10/28
 **/
func (con UserController) SignUp(c *gin.Context) {
	// 1.获取请求参数 2.校验数据有效性
	var signForm *models.SignForm
	err1 := c.ShouldBindJSON(&signForm)
	if err1 != nil {
		// 请求参数有误，直接返回响应
		zap.L().Error("SiginUp with invalid param", zap.Error(err1))

		// 暂时略: 判断err是不是 validator.ValidationErrors类型的errors

		return // 翻译错误
	}

	// 3.业务处理——注册用户
	err2 := service.UserService{}.SignUp(signForm)
	if err2 != nil {
		zap.L().Error("service.SignUp failed", zap.Error(err2))
		if errors.Is(err2, mysql.ErrorUserExit) {
			ResponseError(c, CodeUserExist)
			return
		}
		ResponseError(c, CodeServerBusy)
		return
	}

	ResponseSuccess(c, nil)
}

/**
 * @Author SSWANG
 * @Description //TODO 登录业务
 * @Date 14:32 2022/10/28
 **/
func (con UserController) Login(c *gin.Context) {
	// 1、获取请求参数及参数校验
	// var u *models.User
	var loginForm *models.LoginForm
	if err := c.ShouldBindJSON(&loginForm); err != nil {
		// 请求参数有误，直接返回响应
		zap.L().Error("Login with invalid param", zap.Error(err))

		// 暂时略: 判断err是不是 validator.ValidationErrors类型的errors

		return
	}

	// 2、业务逻辑处理——登录
	// user: *models.User
	var (
		aTokenString string
		rTokenString string
	)
	user, err := service.UserService{}.Login(loginForm, &aTokenString, &rTokenString)
	if err != nil {
		zap.L().Error("service.Login failed", zap.String("username", loginForm.UserName), zap.Error(err))
		if errors.Is(err, mysql.ErrorUserNotExit) {
			ResponseError(c, CodeUserNotExist)
			return
		}
		ResponseError(c, CodeInvalidParams)
		return
	}

	// 3、返回响应
	ResponseSuccess(c, gin.H{
		"user_id":       fmt.Sprintf("%d", user.UserID), //js识别的最大值：id值大于1<<53-1  int64: i<<63-1
		"user_name":     user.UserName,
		"access_token":  aTokenString,
		"refresh_token": rTokenString,
	})
}

/**
 * @Author SSWANG
 * @Description //TODO 刷新 accessToken
 * @Date 10:50 2022/10/29
 **/
func (con UserController) RefreshToken(c *gin.Context) {
	rt := c.Query("refresh_token")
	// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
	// 这里假设Token放在Header的Authorization中，并使用Bearer开头
	// 这里的具体实现方式要依据你的实际业务情况决定
	tokenString := c.Request.Header.Get(jwt.ContextTokenKey)
	if tokenString == "" {
		ResponseErrorWithMsg(c, CodeInvalidToken, "请求头缺少Auth Token")
		c.Abort()
		return
	}

	aToken, rToken, err := jwt.RefreshToken(tokenString, rt)
	fmt.Println(err)
	c.JSON(http.StatusOK, gin.H{
		"access_token":  aToken,
		"refresh_token": rToken,
	})
}
